/**
 * 模拟Promise-ajax形式，操作后台的 Table数据（注： table 等同于「数据库」）
 *
 * 现有实例方法有：
 *  instance.initTable(table)：初始化 数据库
 *    注：！！若 数据库中没 数据，才向 数据库 中增加数据！！
 *
 *  instance.setAll(table)：更改整个 数据库 的数据
 *  instance.set(id, data)：通过 id，更改 已存在的 一行数据
 *
 *  instance.getAll()：获取 table 的所有数据
 *  instance.get(id)：通过 ID 获取指定行的数据
 *
 *  instance.delete(id)：通过 id 删除 table 中已存在的某行数据
 *
 *  instance.append(data)：向 table 的末尾添加一行数据
 */
export class MockAjax {
  constructor(databaseName) {
    if (typeof databaseName !== "string") {
      throw Error("MockAjax 必须有字符串实参 databaseName");
    }
    this.databaseName = databaseName;
  }
  /**
   * 初始化 talbe 的数据
   *    注：！！若 table 中没数据，才向 table 中增加数据！！
   * @param {Array} table
   */
  initTable(table) {
    if (!this._getTable()) {
      this._setTable(table);
    }
  }

  /**
   * 彻底替换整个 table 的数据
   * @param {Array} table
   *
   * @return {Boolean} {status: 'success'} 为数据初始化成功，
   *  {status: 'error'} 为数据初始化失败
   */
  setAll(table) {
    this._setTable(table);
    return this._mockPromiseRes({ status: "success" });
  }

  /**
   * 通过 ID 获取指定数据
   * @param {String} id
   *
   * @return {Promise<Object>} 获取到的「单行」数据
   */
  get(id) {
    const target = this._getTable().find((d) => d?.id == id);
    return this._mockPromiseRes(target);
  }

  /**
   * 获取 table 的所有数据
   *
   * @return {Promise<Array>}
   */
  getAll() {
    const table = this._getTable();
    return this._mockPromiseRes(table);
  }

  /**
   * 通过 id，更改 已存在的 一行数据
   *   注：data 的 key 必须是和 table 每行的 key 一致
   * @param {String} id
   * @param {Object} data
   *
   * @return {Boolean} {status: 'success'} 为更爱成功，
   *  {status: 'error'} 表示不存在 id 的这行数据
   */
  set(id, data) {
    const table = this._getTable();
    const findIndex = table.findIndex((d) => d?.id == id);
    let successData = null,
      errorData = null;
    if (findIndex >= 0) {
      data = {
        ...data,
        id: table[findIndex]?.id,
      };
      table.splice(findIndex, 1, data);
      this._setTable(table);
      successData = { status: "success" };
    } else {
      errorData = { status: "error", message: `table中不存在该ID：${id}` };
    }
    return this._mockPromiseRes(successData, errorData);
  }

  /**
   * 通过 id 删除 table 中已存在的某行数据
   * @param {String} id
   *
   * @return {Boolean} {status: 'success'} 为删除成功，
   *  {status: 'error'} 为删除失败
   */
  delete(id) {
    const table = this._getTable();
    const findIndex = table.findIndex((d) => d?.id == id);
    let successData = null,
      errorData = null;
    if (findIndex >= 0) {
      table.splice(findIndex, 1);
      this._setTable(table);
      successData = { status: "success" };
    } else {
      errorData = { status: "error", message: `table中不存在该ID：${id}` };
    }
    return this._mockPromiseRes(successData, errorData);
  }

  /**
   * 向 table 的末尾添加一行数据
   * @param {Object} data
   *
   * @return {Boolean} {status: 'success'} 为添加成功，
   *  {status: 'error'} 为添加失败
   */
  append(data) {
    const table = this._getTable();
    table.push({
      ...data,
      id: this._randomId(),
    });
    this._setTable(table);
    return this._mockPromiseRes({ status: "success" });
  }

  // 为 每行数据，增加 id
  // @TODO ID偶尔可能重复
  _randomId() {
    return Math.random().toString();
  }

  _getTable() {
    if (this._isJson(localStorage.getItem(this.databaseName))) {
      return JSON.parse(localStorage.getItem(this.databaseName));
    } else {
      throw new Error("不存在数据库！");
    }
  }

  _setTable(data) {
    data.forEach((d) => {
      // 为 每行数据，增加 id
      // @TODO ID偶尔可能重复
      if (!d.id) {
        d.id = this._randomId();
      }
    });

    localStorage.setItem(this.databaseName, JSON.stringify(data));
  }

  // 模拟网络请求：
  //  promise 的1S后，将数据返回
  _mockPromiseRes(successData, errorData) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (errorData) {
          reject(errorData);
        }
        resolve(successData);
      }, 1000);
    });
  }

  _isJson(str) {
    let isJSON = true;

    try {
      JSON.parse(str);
    } catch (err) {
      isJSON = false;
    }

    return isJSON;
  }
}
